using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using PS.Practices.Provisioner;
using PS.Practices.SiteBuilder.Features;
using PS.Practices.SiteBuilder.Features.Schema;

namespace PS.Practices.Util
{
    public static class AclUtil
    {
        public static SPGroup CreateWebGroup(string name, string description, SPWeb web)
        {
            if (string.IsNullOrEmpty(name))
                return null;
         
            if (string.IsNullOrEmpty(description))
            {
                description = string.Empty;
            }
           
            name = ParserUtil.ReplaceLiveFields(name, web);
            //if (name.Contains(",") || name.Contains("'")|| name.Contains(".") || name.Contains(":"))
            //{
            //    name = name.Replace(",", "").Replace("'","").Replace(".","").Replace(":","");
            //}
            Regex regex = new Regex("[^a-z0-9 ]", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
            name = regex.Replace(name, string.Empty);           

            try
            {
                SPGroup group = ResolveSiteGroup(name, web);
                if (group == null)
                {
                    web.SiteGroups.Add(name, web.Author, web.Author, description);
                    return ResolveSiteGroup(name, web);
                }
                else
                {
                    Logger.Info("Group already exists in site group collection: " + name);
                    return group;
                    
                }
            } catch(SPException e)
            {
                Logger.Info("Error while adding a site group: " + name);
                Logger.Error(e);
            }
            return null;
        }

        public static bool DeleteWebGroup(string name, SPWeb web)
        {
            if (string.IsNullOrEmpty(name))
                return false;
            name = ParserUtil.ReplaceLiveFields(name, web);
            try
            {
                web.SiteGroups.Remove(name);
                return true;
            }
            catch (SPException e)
            {
                Logger.Info("Error while removing site group: " + name);
                Logger.Error(e);
            }
            return false;
        }

        public static bool AddPrincipal(SPPrincipal principal, string role, SPSecurableObject securableObject, SPWeb web)
        {
            if (principal != null)
            {
                SPRoleDefinition roleDef = null;
                try
                {
                    roleDef = web.RoleDefinitions[role];
                }
                catch (SPException e)
                {
                    Logger.Info("Error while looking up role definition: " + role);
                    Logger.Error(e);
                    return false;
                }


                Logger.Info("Associating group " + principal.Name + " for role " + role);
                SPRoleAssignment assignment = new SPRoleAssignment(principal);
                assignment.RoleDefinitionBindings.Add(roleDef);
                securableObject.RoleAssignments.Add(assignment);
                
                return true;
            }

            return false;
        }

        public static bool RemovePrincipal(SPPrincipal principal, SPSecurableObject securableObject, SPWeb web)
        {
            if (principal != null)
            {
                securableObject.RoleAssignments.Remove(principal);
                return true;
            }

            return false;
        }

        public static SPUser ResolveUser(string loginName, SPWeb web, bool addIfNotRegistered)
        {
            SPUser user = ResolveUser(loginName, web);

            if (user == null && addIfNotRegistered)
            {
                using (SPGlobalAdmin admin = new SPGlobalAdmin())
                {
                    string displayName = loginName;
                    string email = string.Empty;
                    try
                    {
                        SPUtility.GetFullNameandEmailfromLogin(admin, loginName, out displayName, out email);
                    }
                    catch (Exception)
                    {
                    }

                    if (string.IsNullOrEmpty(displayName)) displayName = loginName;
                    
                    web.AllUsers.Add(loginName, email, displayName, null);
                }
                user = ResolveUser(loginName, web);
            }

            return user;
        }

        public static SPUser ResolveUser(string loginName, SPWeb web)
        {
            try
            {
                return web.AllUsers[loginName];
            }
            catch (SPException)
            {
                return null;
            }            
        }
        
        public static SPGroup ResolveSiteGroup(string name, SPWeb web)
        {
            Regex regex = new Regex("[^a-z0-9 ]", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
            name = regex.Replace(name, string.Empty);

            SPGroup group= null;
            try
            {
                group = web.SiteGroups[name];
            }
            catch (SPException)
            {
                Logger.Info("Could not resolve group name: " + name);
            }
            return group;
        }

        
        internal static void SyncGroupQuickLaunch(SPWeb web, bool fromAssociations)
        {
            //bool first = true;
            //StringBuilder sb = new StringBuilder();
            //StringBuilder groupsSetup = new StringBuilder();
            //object o = web.AllProperties["vti_associategroups"];

            List<SPGroup> groups = new List<SPGroup>();

            if (!fromAssociations)
            {

                foreach (SPRoleAssignment roleAssignment in web.RoleAssignments)
                {
                    SPPrincipal member = roleAssignment.Member;
                    if (member is SPGroup)
                    {
                        //if (!first)
                        //{
                        //    sb.Append(";");
                        //    groupsSetup.Append(";");
                        //}
                        //sb.Append(member.ID);
                        //groupsSetup.Append(member.Name);
                        //first = false;

                        groups.Add((SPGroup)member);
                    }
                }
            } 
            else
            {
                groups.Add(web.AssociatedMemberGroup);
                groups.Add(web.AssociatedOwnerGroup);
                groups.Add(web.AssociatedVisitorGroup);
            
                //SPGroup g = web.AssociatedMemberGroup;
                //if (g != null)
                //{
                //    sb.Append(g.ID + ";");
                //    groupsSetup.Append(g.Name + ";");
                //}

                //g = web.AssociatedOwnerGroup;
                               
                //if (g != null)
                //{
                //    sb.Append(g.ID + ";");
                //    groupsSetup.Append(g.Name + ";");
                //}

                //g = web.AssociatedVisitorGroup;
                //if (g != null)
                //{
                //    sb.Append(g.ID);
                //    groupsSetup.Append(g.Name );
                //}
            }

            SyncGroupQuickLaunch(web, groups);
            
            //using (SPSite site = new SPSite(web.Url))
            //{
            //    using (SPWeb w = site.OpenWeb())
            //    {
            //        w.AllProperties["vti_associategroups"] = "";
            //        w.Update();
            //        w.AllProperties["vti_associategroups"] = sb.ToString();
            //        w.Update();
            //    }
            //}
            
            //Logger.Info("Set groups:" + groupsSetup.ToString());
        }

        public static void SyncGroupQuickLaunch(SPWeb web, IEnumerable<SPGroup> groups)
        {
            //StringBuilder sb = new StringBuilder();
            //StringBuilder groupsSetup = new StringBuilder();
            //foreach (SPPrincipal group in groups)
            //{
            //    if(group != null)
            //    {
            //        sb.Append(group.ID + ";");
            //        groupsSetup.Append(group.Name + ";");
            //    }
            //}

            //if(sb.Length > 0 && sb[sb.Length-1] == ';')
            //{
            //    sb.Remove(sb.Length - 1, 1);
            //}

            ////vti_associategroups does not get persisted in the event any of SPWeb.Associated*Group
            ////accessors were called. therefore. create a new object
            //using (SPSite site = new SPSite(web.Url))
            //{
            //    using (SPWeb w = site.OpenWeb())
            //    {
            //        w.AllProperties["vti_associategroups"] = "";
            //        w.Update();
            //        w.AllProperties["vti_associategroups"] = sb.ToString();
            //        w.Update();

            //        web.AllProperties["vti_associategroups"] = "";
            //        web.Update();
            //        web.AllProperties["vti_associategroups"] = sb.ToString();
            //        web.Update();
            //    }
            //}

            //Logger.Info("Set groups:" + groupsSetup);
            //web.AssociatedGroups.Clear();
            //foreach (SPGroup group in groups)
            //{
            //    //try
            //    //{
            //        web.AssociatedGroups.Add(group);
            //    //}
            //    //catch (InvalidCastException)
            //    //{}
            //}
        }

        public static void AddToSecurityGroup(string groupName, SPUser user, SPWeb web)
        {
            SPGroup group = ResolveSiteGroup(groupName, web);

            group.AddUser(user);
        }
    }
}